/*
 * Alloy Analyzer 4 -- Copyright (c) 2006-2008, Felix Chang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package edu.ut.ece382c.valloy.parser;

import java.util.List;
import edu.mit.csail.sdg.alloy4.ConstList;
import edu.mit.csail.sdg.alloy4.ErrorFatal;
import edu.mit.csail.sdg.alloy4.Pos;
import edu.mit.csail.sdg.alloy4.Util;
import edu.ut.ece382c.valloy.ast.Expr;
import edu.ut.ece382c.valloy.ast.ExprCustom;
import edu.ut.ece382c.valloy.ast.ExprVar;


/** Immutable; this class represents a macro. */

final class Macro extends ExprCustom {

    /** If nonnull, this is a private macro. */
    final Pos isPrivate;

    /** The module that defined this. */
    private final Module realModule;

    /** The name of the macro. */
    private final String name;

    /** The list of parameters (can be an empty list) */
    private final ConstList<ExprVar> params;

    /** The list of arguments (can be an empty list) (must be equal or shorter than this.params) */
    private final ConstList<Expr> args;

    /** The macro body. */
    private final Expr body;

    /** Construct a new Macro object. */
    private Macro(Pos pos, Pos isPrivate, Module realModule, String name, List<ExprVar> params, List<Expr> args, Expr body) {
        super(pos, new ErrorFatal(pos, "Incomplete call on the macro \""+name+"\""));
        this.realModule = realModule;
        this.isPrivate = isPrivate;
        this.name = name;
        this.params = ConstList.make(params);
        this.args = ConstList.make(args);
        this.body = body;
    }

    /** Construct a new Macro object. */
    Macro(Pos pos, Pos isPrivate, Module realModule, String name, List<ExprVar> params, Expr body) {
        this(pos, isPrivate, realModule, name, params, null, body);
    }

    Macro addArg(Expr arg) {
        return new Macro(pos, isPrivate, realModule, name, params, Util.append(args,arg), body);
    }

    Expr changePos(Pos pos) {
        return new Macro(pos, isPrivate, realModule, name, params, args, body);
    }

    /** {@inheritDoc} */
    @Override public void toString(StringBuilder out, int indent, boolean newline) {
    	for(int i=0; i<indent && newline; i++) { out.append(' '); }
    	
    	//
    	// TODO VALLOY this is broken
    	//
    	if(isPrivate != null){
    		out.append("private ");
    	}
    	
    	out.append("let ").append(name);
    	
    	for(ExprVar v:params){
    		v.toString(out,indent, false);
    	}
    	
    	body.toString(out,indent, false);
    }

    /** {@inheritDoc} */
    public int getDepth() {
        int max = body.getDepth();
        for(Expr x: args) { int tmp=x.getDepth(); if (max<tmp) max=tmp; }
        return 1 + max;
    }

    /** {@inheritDoc} */
    @Override public String toString() {    	
    	StringBuilder sb = new StringBuilder();
    	toString(sb,0, false);
    	return sb.toString();
    }
}
